using Godot;
using System;
using DialogueManagerRuntime;

public partial class DialogueTrigger : Area2D // 如果是2D游戏，请继承 Area2D
{
    [ExportGroup("对话设置")]
    [Export] public Resource DialogueResource; // 对话文件
    [Export] public string DialogueStart = "start"; // 对话标题
    [Export] public PackedScene BalloonScene; // 气泡场景
    [ExportGroup("触发规则")]
    [Export] public bool TriggerOnce = false; // 是否只触发一次
    [Export] public bool LockPlayerDuringDialogue = true; // 是否对话时锁定玩家

    // 内部状态
    private bool _hasTriggered = false; // 记录是否已经触发过（用于 TriggerOnce）
    private bool _isSpeakingLocal = false; // 记录当前这个触发器是否正在说话

    // 【核心技巧】静态计数器：记录全游戏当前有几个触发器正在活跃
    // 作用：防止触发器A结束时，误把触发器B正在进行的对话给解锁了
    private static int _activeDialogueCount = 0;

    public override void _Ready()
    {
        BodyEntered += OnBodyEntered;

        // 监听 Dialogue Manager 的全局结束信号
        var dialogueManager = GetNodeOrNull("/root/DialogueManager");
        if (dialogueManager != null)
        {
            dialogueManager.Connect("dialogue_ended", Callable.From((Resource res) => OnDialogueEnded(res)));
        }
    }

    private void OnBodyEntered(Node body)
    {
        // 1. 检查是否是玩家
        if (body.Name != "Player" && !body.IsInGroup("player")) return;

        // 2. 检查是否是“一次性触发”且“已经触发过”
        if (TriggerOnce && _hasTriggered) return;

        // 3. 检查“当前这个对话”是否正在进行
        // 如果正在说这句话，玩家还在里面乱晃，不要重头开始
        if (_isSpeakingLocal) return;

        // --- 通过所有检查，开始对话 ---
        StartDialogue(body);
    }

    private void StartDialogue(Node player)
    {
        if (DialogueResource == null)
        {
            GD.PrintErr($"{Name}: 没有设置 Dialogue Resource！");
            return;
        }

        // 更新状态
        _hasTriggered = true;     // 标记已触发
        _isSpeakingLocal = true;  // 标记正在说话
        _activeDialogueCount++;   // 全局活跃对话 +1

        // 处理锁定逻辑
        if (LockPlayerDuringDialogue)
        {
            TogglePlayerControl(player, false); // 禁用控制
        }

        // 总是显示鼠标（防止FPS游戏卡死）
        Input.MouseMode = Input.MouseModeEnum.Visible;

        // 调用 Dialogue Manager
        var dialogueManager = GetNode("/root/DialogueManager");
        DialogueManager.ShowDialogueBalloonScene(BalloonScene, DialogueResource, DialogueStart);
    }

    private void OnDialogueEnded(Resource resource)
    {
        // 只有当结束的资源是“我”负责的资源时，才处理
        if (resource == DialogueResource)
        {
            // 如果我之前处于说话状态，现在结束了
            if (_isSpeakingLocal)
            {
                _isSpeakingLocal = false;
                _activeDialogueCount--; // 全局活跃对话 -1
            }

            // 只有当全局没有任何对话在进行时，才恢复玩家控制
            // 这解决了“走进对话B导致对话A结束，A结束时错误地解锁了玩家”的问题
            if (_activeDialogueCount <= 0)
            {
                _activeDialogueCount = 0; // 归零防溢出

                // 恢复控制
                // 注意：这里需要再次获取玩家节点，因为OnDialogueEnded没有body参数
                // 最简单的办法是去获取场景里的 Player 节点
                var player = GetTree().GetFirstNodeInGroup("player");
                if (player != null && LockPlayerDuringDialogue)
                {
                    TogglePlayerControl(player, true); // 恢复控制
                }

                // (可选) 恢复鼠标锁定，看你的游戏类型
                // Input.MouseMode = Input.MouseModeEnum.Captured;
            }
        }
    }

    // 这是一个通用方法，用来控制玩家能不能动
    // 你需要根据你的玩家脚本修改这里
    private void TogglePlayerControl(Node player, bool canMove)
    {
        // 方法A：如果你的玩家脚本里有一个 public bool CanMove;
        // player.Set("CanMove", canMove);

        // 方法B：简单粗暴法 - 禁用物理处理 (玩家会定住，如果是CharacterBody3D)
        // 优点：通用，不用改玩家代码
        // 缺点：如果玩家在空中，会悬空（物理暂停了）
        player.SetPhysicsProcess(canMove);

        // 方法C (推荐)：如果你的玩家脚本叫 PlayerController，可以强转
        // if (player is PlayerController p) p.SetInputEnabled(canMove);
    }
}